package com.jsbs.iam.component.filter;


import com.alibaba.fastjson.JSONObject;
import com.jsbs.iam.component.constant.Constants;
import com.jsbs.iam.component.dto.Result;
import com.jsbs.iam.component.dto.SessionInfo;
import com.jsbs.iam.component.utils.HttpUtil;
import com.jsbs.iam.component.utils.Json;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;


import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 会话认证过滤器
 *
 * @author junwc
 */
@Component
public class IdentityFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(IdentityFilter.class);

    /**
     * 登录认证白名单
     */
    @Value("${iam.ident.white.url}")
    private String whiteUrl;

    /**
     * 登录接入标识 true 接入，false 不接入
     */
    @Value("${iam.ident.access.flag}")
    private boolean identAccessFlag;

    /**
     * IAM账户中心域名
     */
    @Value("${iam.ident.domain}")
    private String iamIdentDomain;

    /**
     * IAM账户中心会话认证请求URL地址
     */
    @Value("${iam.ident.url}")
    private String iamIdentUrl;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String url = request.getRequestURI();
        log.info("identity filter for requestURL: {}", url);
        // 是否接入账户中 true是 false否
        if (identAccessFlag) {
            // 白名单
            List<String> whiteUrlList = new ArrayList<>();
            if (StringUtils.isNotEmpty(whiteUrl)) {
                whiteUrlList = Arrays.asList(whiteUrl.split(","));
            }
            // 白名单为空 或 URL非白名单 则需要进行会话认证请求转发至IAM会话认证接口
            if (CollectionUtils.isEmpty(whiteUrlList) || !whiteUrlList.contains(url)) {
                Cookie[] cookies = request.getCookies();
                if (cookies == null) {
                    response.sendError(HttpStatus.SC_UNAUTHORIZED, "token异常");
                    return;
                }
                // token
                String token = null;
                for (int i = 0; i < cookies.length; i++) {
                    Cookie ck = cookies[i];
                    if (ck.getName().equals(Constants.HEADER_TOKEN)) {
                        token = ck.getValue();
                    }
                }
                // token判空
                if(StringUtils.isEmpty(token)){
                    response.sendError(HttpStatus.SC_UNAUTHORIZED, "token异常");
                    return;
                }
                // 入参
                Map<String, Object> param = new HashMap<>();
                param.put(Constants.TOKEN, token);
                param.put(Constants.SERVER_NAME, request.getServerName());
                log.info("Route=>IdentityFilter method=doFilter 会话认证请求服务域名serverName:{}", request.getServerName());
                // 请求账户中心进行会话认证
                String resultStr = HttpUtil.postJson(iamIdentDomain + iamIdentUrl, Json.toJsonString(param));
                if (StringUtils.isEmpty(resultStr)) {
                    log.info("Route=>IdentityFilter method=doFilter 会话认证发生异常，入参：{}", token);
                    throw new RuntimeException("会话认证发生异常");
                }
                log.info("Route=>IdentityFilter method=doFilter 会话认证返回结果：{}", resultStr);
                Result result = Json.parseJson(resultStr, Result.class);
                // 会话认证失败
                if (!result.isSuccess()) {
                    response.sendError(HttpStatus.SC_UNAUTHORIZED, "会话认证失败");
                    return;
                }
                // 返回的用户信息
                SessionInfo sessionInfo = JSONObject.parseObject(Json.toJsonString(result.getData()), SessionInfo.class);
                sessionInfo.setUserType(request.getHeader(Constants.USER_TYPE));
                HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(request);
                sessionInfo.setUserType(request.getHeader(Constants.USER_TYPE));
                // 请求头设置用户信息
                setHeaderInfo(requestWrapper, token, sessionInfo);
                filterChain.doFilter(requestWrapper, response);
                return;
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    /**
     * 功能描述：请求头设置用户信息
     * @param requestWrapper
     * @param token
     * @param sessionInfo
     */
    private void setHeaderInfo(HeaderMapRequestWrapper requestWrapper, String token, SessionInfo sessionInfo) {
        // token
        requestWrapper.addHeader(Constants.HEADER_TOKEN, token);
        // 归属租户
        requestWrapper.addHeader(Constants.COMPANY_CODE, sessionInfo.getCompanyCode());
        // 组织类型编码
        requestWrapper.addHeader(Constants.ORG_TYPE_CODE, sessionInfo.getOrgTypeCode());
        // 应用编码
        requestWrapper.addHeader(Constants.APPLY_CODE, sessionInfo.getApplyCode());
        // 登录人名字
        requestWrapper.addHeader(Constants.NAME, sessionInfo.getName());
        // 登录人编码
        requestWrapper.addHeader(Constants.USER_CODE, sessionInfo.getUserCode());
        // 登录人业务系统ID
        requestWrapper.addHeader(Constants.USER_ID, sessionInfo.getUserId());
        // 登录人手机号
        requestWrapper.addHeader(Constants.PHONE, sessionInfo.getPhone());
        // 用户类型，0普通用户 1管理员用户
        requestWrapper.addHeader(Constants.USER_TYPE, sessionInfo.getUserType());
    }

    @Override
    public void destroy() {

    }
}